package com.tianji.learning.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.remark.RemarkClient;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.enums.QuestionStatus;
import com.tianji.learning.pojo.dto.ReplyDTO;
import com.tianji.learning.pojo.po.InteractionQuestion;
import com.tianji.learning.pojo.po.InteractionReply;
import com.tianji.learning.mapper.InteractionReplyMapper;
import com.tianji.learning.pojo.query.ReplyPageQuery;
import com.tianji.learning.pojo.vo.ReplyVO;
import com.tianji.learning.service.IInteractionQuestionService;
import com.tianji.learning.service.IInteractionReplyService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.tianji.common.constants.Constant.DATA_FIELD_NAME_CREATE_TIME;

/**
 * <p>
 * 互动问题的回答或评论 服务实现类
 * </p>
 */
@Service
@RequiredArgsConstructor
public class InteractionReplyServiceImpl extends ServiceImpl<InteractionReplyMapper, InteractionReply> implements IInteractionReplyService {

    private final IInteractionQuestionService questionService;
    private final UserClient userClient;
    private final RabbitMqHelper mqHelper;
    private final RemarkClient remarkClient;

    /**
     * 新增回答或评论 09
     *
     * @param replyDTO
     */
    @Override
    @Transactional
    public void saveReply(ReplyDTO replyDTO) {
        // 新增回答
        InteractionReply reply = BeanUtils.copyBean(replyDTO, InteractionReply.class);
        reply.setUserId(UserContext.getUser());
        save(reply);

        // 累加评论数或者累加回答数
        boolean isAnswer = replyDTO.getAnswerId() == null;
        // 判断当前回复的类型是否是回答
        if (!isAnswer) {
            // 回答：尝试更新问题表中的状态、 最近一次回答、回答数量
            if (ObjectUtil.isEmpty(replyDTO.getTargetReplyId())) {
                questionService.lambdaUpdate()
                        .set(InteractionQuestion::getLatestAnswerId, reply.getId())
                        .setSql("answer_times = answer_times + 1")
                        .set(replyDTO.getIsStudent(), InteractionQuestion::getStatus, QuestionStatus.UN_CHECK.getValue())
                        .eq(InteractionQuestion::getId, reply.getQuestionId())
                        .update();
            }
        } else {
            // 评论:需要更新上级回答的评论数量
            lambdaUpdate().setSql("reply_times = reply_times + 1")
                    .eq(InteractionReply::getId, reply.getAnswerId())
                    .update();
        }
    }

    /**
     * 分页查询回答或评论 10
     *
     * @param pageQuery
     * @param isStudent
     * @return PageDTO<ReplyVO>
     */
    @Override
    public PageDTO<ReplyVO> queryReplyPage(ReplyPageQuery pageQuery, boolean isStudent) {
        Long answerId = pageQuery.getAnswerId();
        Long questionId = pageQuery.getQuestionId();
        if (ObjectUtil.isAllEmpty(answerId, questionId)) {
            throw new BadRequestException("问题或回答id不能都为空");
        }

        // 标记当前是查询问题下的回答
        boolean isQueryAnswer = questionId != null;
        // 分页查询数据
        Page<InteractionReply> page = lambdaQuery()
                .eq(isQueryAnswer, InteractionReply::getQuestionId, questionId)
                .eq(InteractionReply::getAnswerId, isQueryAnswer ? 0L : answerId)
                .eq(isStudent, InteractionReply::getHidden, false)
                .page(pageQuery.toMpPage(new OrderItem(DATA_FIELD_NAME_CREATE_TIME, true)));

        List<InteractionReply> records = page.getRecords();
        if (CollectionUtil.isEmpty(records)) {
            return PageDTO.empty(page);
        }

        // 需要查询：提问者信息、回复目标信息、当前用户是否点赞
        Set<Long> userIds = new HashSet<>();
        Set<Long> answerIds = new HashSet<>();
        Set<Long> targetUserIds = new HashSet<>();

        for (InteractionReply record : records) {
            if (!record.getAnonymity() || isStudent) {
                userIds.add(record.getUserId());
            }
            answerIds.add(record.getId());
            targetUserIds.add(record.getTargetUserId());
        }

        // 查询目标回复，如果目标回复不是匿名，则需要查询出目标回复的用户信息
        targetUserIds.remove(null);
        if (targetUserIds.size() > 0) {
            userIds.addAll(targetUserIds);
        }
        Map<Long, UserDTO> userMap = new HashMap<>(userIds.size());
        if (userIds.size() > 0) {
            List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
            userMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, Function.identity()));
        }

        // 查询用户点赞状态
        Set<Long> bizLiked = remarkClient.isBizLiked(answerIds);

        List<ReplyVO> voList = new ArrayList<>(records.size());
        for (InteractionReply record : records) {
            ReplyVO vo = BeanUtils.copyBean(record, ReplyVO.class);

            // 非匿名或者是学生就获取到具体用户信息
            if (!record.getAnonymity() || isStudent) {
                UserDTO userDTO = userMap.get(record.getUserId());
                if (ObjectUtil.isNotNull(userDTO)) {
                    vo.setUserIcon(userDTO.getIcon());
                    vo.setUserName(userDTO.getName());
                    vo.setUserType(userDTO.getType());
                }
            }

            // 如果存在评论的目标，则需要设置目标的用户信息
            if (record.getTargetReplyId() != null) {
                UserDTO userDTO = userMap.get(record.getTargetUserId());
                if (ObjectUtil.isNotNull(userDTO)) {
                    vo.setTargetUserName(userDTO.getName());
                }
            }
            // 点赞状态
            vo.setLiked(bizLiked.contains(record.getId()));

            voList.add(vo);
        }
        return PageDTO.of(page, voList);
    }

    /**
     * 根据id查询回答或评论 11
     *
     * @param id
     */
    @Override
    public ReplyVO queryReplyById(Long id) {
        InteractionReply reply = getById(id);

        Set<Long> userIds = new HashSet<>();
        userIds.add(reply.getUserId());

        // 查询评论目标，如果评论目标不是匿名，则需要查询出目标回复的用户id
        if (ObjectUtil.isNotEmpty(reply.getTargetReplyId())) {
            // 获取回复者回复数据
            InteractionReply targetReply = getById(reply.getTargetReplyId());
            if (!targetReply.getAnonymity()) {
                userIds.add(targetReply.getUserId());
            }
        }

        Map<Long, UserDTO> userDTOMap = new HashMap<>();
        if (userIds.size() > 0) {
            List<UserDTO> userDTOS = userClient.queryUserByIds(userIds);
            userDTOMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, Function.identity()));
        }

        ReplyVO vo = BeanUtils.copyBean(reply, ReplyVO.class);

        // 查询用户点赞状态，通过调用点赞微服务查询该业务是否被点赞，返回用户点赞的业务ID集合
        Set<Long> bizLiked = remarkClient.isBizLiked(CollUtils.singletonList(id));
        vo.setLiked(bizLiked.contains(id));

        UserDTO userDTO = userDTOMap.get(reply.getUserId());
        if (ObjectUtil.isNotNull(userDTO)) {
            vo.setUserName(userDTO.getName());
            vo.setUserIcon(userDTO.getIcon());
            vo.setUserType(userDTO.getType());
        }

        UserDTO targetUser = userDTOMap.get(reply.getTargetUserId());
        if (ObjectUtil.isNotNull(targetUser)) {
            vo.setTargetUserName(targetUser.getName());
        }
        return vo;
    }

    /**
     * 隐藏或显示评论 12
     *
     * @param id
     * @param hidden
     */
    @Override
    @Transactional
    public void hiddenReply(Long id, Boolean hidden) {
        InteractionReply reply = getById(id);
        if (ObjectUtil.isNull(reply)) {
            return;
        }

        InteractionReply interactionReply = new InteractionReply();
        interactionReply.setId(id);
        interactionReply.setHidden(hidden);
        updateById(interactionReply);

        // 隐藏评论，先判断是否是回答，回答才需要隐藏下属评论
        if (ObjectUtil.isNotEmpty(reply.getAnswerId())) {
            // 有answer ID表示自己是评论，无需处理
            return;
        }

        // 表示是回答，对回答进行隐藏需要把下级评论也隐藏
        lambdaUpdate().set(InteractionReply::getHidden, hidden)
                .eq(InteractionReply::getAnswerId, id)
                .update();
    }
}
